package com.ivanceras.server.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import com.ivanceras.shared.db.EntityManager;
import com.ivanceras.shared.db.ModelDef;
import com.ivanceras.shared.db.PolymorphicModel;
import com.ivanceras.shared.db.SchemaTable;
import com.ivanceras.shared.exception.DatabaseException;
import com.ivanceras.shared.exception.ModelDefinitionNotFoundException;
import com.ivanceras.shared.exception.PolymorphicTableException;
import com.ivanceras.shared.util.Configuration;

public class PolyMorphicModelList {
	
	static HashMap<String, PolymorphicModel> plist = new HashMap<String, PolymorphicModel>();
	static HashMap<String, ModelDef> modelDefList = new HashMap<String, ModelDef>();
	
	public PolyMorphicModelList(EntityManager em){
		init();
		try {
			generateCorrectModelList(em);
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}
	
	static void init(){
	
		PolymorphicModel model1 = new PolymorphicModel("opt_out", "oomechanism", "oomechanism_id");
		String[] coverage1 = {"http_opt_out", "email_opt_out", "js_opt_out"};
		model1.setCoverage(coverage1);
		
		PolymorphicModel model2 = new PolymorphicModel("opt_out_scope", "scope_type", "scope_type_id");
		String[] coverage2 = {"organization", "domains", "tracker"};
		model2.setCoverage(coverage2);
		
		PolymorphicModel model3 = new PolymorphicModel("tracker", "ttechnique", "ttechnique_tid");
		String[] coverage3 = {"thirdpty_cookie", "firstpty_cookie", "html5_storage"};
		model3.setCoverage(coverage3);
		
		plist.put(model1.getModelName(), model1);
		plist.put(model2.getModelName(), model2);
		plist.put(model3.getModelName(), model3);
		
	}
	
	
	public boolean contains(String tableName){
		return modelDefList.containsKey(tableName);
	}
	
	public static ModelDef generatePolyMorpModelStubs(EntityManager em, PolymorphicModel pmodel) throws DatabaseException{
		SchemaTable[] schtable = DAOGenerator.getTableNames(em.getDB(), Configuration.dbUser, pmodel.getModelName().toLowerCase());
		String schema = schtable[0].getSchema();
		
		String tableName = pmodel.getModelName();
		
		ModelDef model = em.getDB().getModelMetaData(schema, tableName);//original model
		
		//add the polymorphic information
		
		String[] coverage = pmodel.getCoverage();
		List<String> hasOneList = new ArrayList<String>();
		List<String> hasOneReferredColumn = new ArrayList<String>();
		List<String> hasOneForeignColumn = new ArrayList<String>();
		
		for(String cov : coverage){
			ModelDef coverageModel = em.getDB().getModelMetaData(schema, cov);
			String[] primaryAttributes = coverageModel.getPrimaryAttributes();
			if(primaryAttributes.length == 1){
				hasOneList.add(cov);
				hasOneReferredColumn.add(primaryAttributes[0]);
				hasOneForeignColumn.add(pmodel.getRecordAttribute());
			}else{
				throw new PolymorphicTableException("primary columns of "+cov+" must be only 1 when used as a coverage in polymorphic models in "+tableName);
			}
		}
		model.setHasOne(hasOneList.toArray(new String[hasOneList.size()]));
		model.setHasOneReferredColumn(hasOneReferredColumn.toArray(new String[hasOneReferredColumn.size()]));
		model.setHasOneForeignColumn(hasOneForeignColumn.toArray(new String[hasOneForeignColumn.size()]));
	
		return model;
	}
	
	static void generateCorrectModelList(EntityManager em) throws DatabaseException{
		for(Entry<String, PolymorphicModel> entry : plist.entrySet()){
			PolymorphicModel pmodel = entry.getValue();
			ModelDef model = generatePolyMorpModelStubs(em, pmodel);
			modelDefList.put(model.getModelName(), model);
		}
	}

	public ModelDef getModelDefinition(String table) throws DatabaseException{
		if(contains(table)){
			return modelDefList.get(table);
		}else{
			try {
				throw new ModelDefinitionNotFoundException("Unable to find Polymorphic model: "+table);
			} catch (ModelDefinitionNotFoundException e) {
				e.printStackTrace();
				throw new DatabaseException(e.getMessage());
			}
		}
	}
	
}
